#ifndef ERRORPRINTER_H
#define ERRORPRINTER_H

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

class ErrorPrinter {
public:
  class Error {
  public:
    Error(size_t line, const std::string &heap, const std::string &msg) : line(line), heap(heap), msg(msg) {}

    Error &operator<<(int value) {
      ints.push_back(value);
      return *this;
    }

    const std::string errorString() const {
      std::string res = " - " + msg;

      std::ostringstream buf;

      for (size_t i = 0; i < ints.size(); i++) {
        buf.clear();
        buf << "{" << i << "}";
        size_t pos = res.find(buf.str());
        if (pos == std::string::npos)
          break;
        buf.str("");
        buf << ints[i];
        res.replace(pos, 3, buf.str());
        buf.str("");
      }
      return heap + res;
    }

    size_t line;
    std::vector<int> ints;
    std::string heap, msg;
  };

  void setFile(const std::string &file) { 
    errors.clear();
    this->file = file; 
  }

  Error &addError(size_t line, const std::string &heap, const std::string &msg) {
    Error *error = new Error(line, heap, msg);
    errors.push_back(error);
    return *error;
  }

  void printResult() {
    if (errors.size() == 0) {
      std::cout << file << ": 0 errors" << std::endl;
      return;
    }
    std::cout << file << ":" << errors[0]->line << ": " << errors[0]->errorString() << std::endl;

    if (errors.size() > 1)
      std::cout << file << ": - another " << (errors.size()-1) << " error(s)" << std::endl;
    errors.clear();
  }

  std::vector<Error*> errors;
  std::string file;
};

#endif //ERRORPRINTER_H
